//! 系统内核汇编及异常入口

use crate::{
    bsp::{__console_init, __early_init, __late_init, __secondary_init},
    irq::{
        irq_init, irq_init_cpu,
        irqflags::{irqs_disabled, local_irq_restore, local_irq_save},
    },
    processor::{cpu_relax, set_this_processor_id},
    sched::{
        preempt::{preempt_count, preempt_disable},
        schedule::{sched_init, sched_init_cpu},
        task::{current_fast, early_task_init, task_init},
    },
    smp::{CPU_ONLINE, smp_init},
    space::{
        kalloc::kalloc_init,
        mm::{mm_init, mm_init_cpu},
    },
    time::{time_init, time_init_cpu},
};

cfg_if::cfg_if! {
    if #[cfg(target_arch = "aarch64")] {
        mod aarch64;
        use aarch64::arch_secondary_info;
    } else {
        mod dummy;
        use dummy::arch_secondary_info;
    }
}

fn irq_restore_and_preempt_disabled() {
    debug_assert!(irqs_disabled(), "Interrupts were enabled early");
    debug_assert_eq!(preempt_count(), 0, "Preempt count is not 0");
    // 抢占禁用
    preempt_disable();
    // 开启系统中断
    local_irq_restore(0);
}

#[doc(hidden)]
#[unsafe(export_name = "__start_kernel")]
pub unsafe fn start_kernel() -> ! {
    // 中断关闭
    local_irq_save();

    // 设置处理器标识 id
    set_this_processor_id(0);
    CPU_ONLINE.set(0);

    early_task_init();
    unsafe {
        __early_init();
        __console_init();
    }

    kalloc_init();
    mm_init();
    task_init();
    irq_init();
    time_init();
    sched_init();
    smp_init();

    irq_restore_and_preempt_disabled();

    unsafe {
        __late_init();
    }
    loop {
        cpu_relax();
    }
}

#[doc(hidden)]
#[unsafe(export_name = "__secondary_start_kernel")]
pub unsafe fn secondary_start_kernel() -> ! {
    // 中断关闭
    local_irq_save();

    let cpu = current_fast().cpu();
    set_this_processor_id(cpu);

    mm_init_cpu();
    irq_init_cpu();
    time_init_cpu();
    sched_init_cpu();

    arch_secondary_info();
    CPU_ONLINE.set(cpu);

    irq_restore_and_preempt_disabled();

    unsafe {
        __secondary_init();
    }
    loop {
        cpu_relax();
    }
}
